﻿// ******************************************************
// SMS.Framework
// SMS.Framework.Scientific.Astronomy
// Moon.cs
// Copyright (c) 2009, SMS Framework. All Rights Reserved.
// ******************************************************

using System;
using SMS.Framework.Core;

namespace SMS.Framework.Scientific.Astronomy
{

    public class Moon
    {

        #region CONSTRUCTORS

            /// <summary>
            /// Contructor of the class.
            /// Class to work with the astronomy data relationship with the Moon. 
            /// The cycle of the Moon around the Earth is 29 days, 12 hours, 44 minutes, 2.8 seconds. 29.53059 days. 
            /// </summary>
            public Moon()
            {
            } // Moon

        #endregion

            // Months with their names and values from 0 to 11 
            private MoonMonthValue[] Months = { new MoonMonthValue { NameMonth = "January", ValueMonth = 0 }, 
                                                new MoonMonthValue { NameMonth = "February", ValueMonth = 1 }, 
                                                new MoonMonthValue { NameMonth = "March", ValueMonth = 0 }, 
                                                new MoonMonthValue { NameMonth = "April", ValueMonth = 1 }, 
                                                new MoonMonthValue { NameMonth = "May", ValueMonth = 2 }, 
                                                new MoonMonthValue { NameMonth = "June", ValueMonth = 3 }, 
                                                new MoonMonthValue { NameMonth = "July", ValueMonth = 4 }, 
                                                new MoonMonthValue { NameMonth = "August", ValueMonth = 5 }, 
                                                new MoonMonthValue { NameMonth = "September", ValueMonth = 7 }, 
                                                new MoonMonthValue { NameMonth = "October", ValueMonth = 7 }, 
                                                new MoonMonthValue { NameMonth = "November", ValueMonth = 9 }, 
                                                new MoonMonthValue { NameMonth = "December", ValueMonth = 9 } }; 
            
            /// <summary> 
            /// The Epact of the Moon, is an internal value relationship with the Moon. Each year, we will have a new Epact value. 
            /// </summary> 
            /// <param name="year"></param> 
            /// <returns></returns> 
            /// <remarks></remarks> 
            public byte EpactValue(int year) 
            { 
                int rest = year % 19; 
                byte value = Convert.ToByte(rest * 11);
                while (value > 29) { 
                    value -= 30; 
                } 
                // Substract 1 to the result 
                if (value != 0) { 
                    value -= 1; 
                } 
                else { 
                    value = 29; 
                } 
                // Return the value of the Epact of the Moon 
                return value; 
            } 
            // EpactValue 
            
            /// <summary> 
            /// The Epact of the Moon, is an internal value relationship with the Moon. Each year, we will have a new Epact value. 
            /// </summary> 
            /// <param name="dateValue">Date to calculate the Epact year of the Moon.</param> 
            /// <returns>Returns the value of the Epact.</returns> 
            /// <remarks></remarks> 
            public byte EpactValue(System.DateTime dateValue) 
            { 
                // Call to EpactaYear function with year parameter, 
                // and return the value of the Epacta. 
                return EpactValue(dateValue.Year); 
            } 
            // EpactYear 
            
            /// <summary> 
            /// Calculates the age of the Moon. 
            /// Another feature about the age of the moon is the Meton cycle. 
            /// The Meton cycle repeat the same phases in the same date each 19 years. 
            /// </summary> 
            /// <param name="dateValue">Date to calculate the age of the Moon.</param> 
            /// <returns>Returns the value of the age of the Moon.</returns> 
            /// <remarks></remarks> 
            public double Age(System.DateTime dateValue) 
            { 
                // Date 
                byte dayData = Convert.ToByte(dateValue.Day); 
                byte monthData = Convert.ToByte(dateValue.Month); 
                int yearData = Convert.ToByte(dateValue.Year); 
                // Time 
                byte hoursData = Convert.ToByte(dateValue.Hour); 
                byte minutesData = Convert.ToByte(dateValue.Minute); 
                byte secondsData = Convert.ToByte(dateValue.Second); 
                // Get the Epacta value of the year 
                double value = EpactValue(yearData); 
                // Add the days 
                value += dayData; 
                // Add the months value according with the Months structure 
                value += Months[monthData - 1].ValueMonth; 
                // Add 1 if the year is bisiest 
                value += Calculate.LeapYear(yearData) ? 1 : 0; 
                // While the value is greater than 29, substract 30 to the value 
                while (value > 29) { 
                    value -= 30; 
                } 
                // Add the time 
                double portionMoonAge = (hoursData * 3600 + minutesData * 60 + secondsData) / 86400; 
                // Return the final value 
                return value + portionMoonAge; 
            } 
            // Age 
            
            /// <summary> 
            /// Calculates the luminosity of the Moon. 
            /// </summary> 
            /// <param name="dateValue">Date to calculate the luminosity of the Moon. You can use a large date (date + time) too.</param> 
            /// <returns>Returns the luminosity value in a double value.</returns> 
            /// <remarks></remarks> 
            public double Luminosity(System.DateTime dateValue) 
            { 
                // Indicates the luminosity of the Moon in the date passed as parameter 
                float ageValue = (float)Age(dateValue); 
                // We get the light (lit) value of the Moon 
                if (ageValue > 14.8347225) 
                { 
                    return 200 - (ageValue * 100) / 14.8347225f; 
                } 
                else 
                { 
                    return (ageValue * 100) / 14.8347225f; 
                } 
                // Return the luminosity value of the Moon 
                return (ageValue * 100) / 14.8347225f; 
            } 
            // Luminosity 
            
            public MoonPhase Phase(System.DateTime dateValue) 
            { 
                // Indicates the phase of the Moon in the date passed as parameter 
                // In the first step will get the integer value of the age of the moon 
                byte phaseValue = Convert.ToByte(Age(dateValue)); 
                // In the second step will process the age with the moon phase 
                MoonPhase moonPhase = MoonPhase.WanningCrescent;
                switch (phaseValue) 
                { 
                    case 0: 
                    case 1: 
                    case 2: 
                    case 3:
                        moonPhase = MoonPhase.NewMoon;
                        break;
                    case 4: 
                    case 5: 
                    case 6:
                        moonPhase = MoonPhase.WaxingCrescent;
                        break;
                    case 7: 
                    case 8: 
                    case 9:
                        moonPhase = MoonPhase.FirstQuarter;
                        break;
                    case 10: 
                    case 11: 
                    case 12: 
                    case 13:
                        moonPhase = MoonPhase.WaxingGibbous;
                        break;
                    case 14: 
                    case 15: 
                    case 16: 
                    case 17:
                        moonPhase = MoonPhase.FullMoon;
                        break;
                    case 18: 
                    case 19: 
                    case 20: 
                    case 21:
                        moonPhase = MoonPhase.WanningGibbous;
                        break;
                    case 22: 
                    case 23: 
                    case 24: 
                    case 25:
                        moonPhase = MoonPhase.LastQuarter;
                        break;
                    case 26: 
                    case 27: 
                    case 28: 
                    case 29: 
                    default:
                        moonPhase = MoonPhase.WanningCrescent;
                        break;
                }
                return moonPhase;
            } 
        } // Phase 
    
 
} // SMS.Framework.Scientific.Astronomy